package com.sun.lib.clip;
/*
 *
 * #                                                   #
 * #                       _oo0oo_                     #
 * #                      o8888888o                    #
 * #                      88" . "88                    #
 * #                      (| -_- |)                    #
 * #                      0\  =  /0                    #
 * #                    ___/`---'\___                  #
 * #                  .' \\|     |# '.                 #
 * #                 / \\|||  :  |||# \                #
 * #                / _||||| -:- |||||- \              #
 * #               |   | \\\  -  #/ |   |              #
 * #               | \_|  ''\---/''  |_/ |             #
 * #               \  .-\__  '-'  ___/-. /             #
 * #             ___'. .'  /--.--\  `. .'___           #
 * #          ."" '<  `.___\_<|>_/___.' >' "".         #
 * #         | | :  `- \`.;`\ _ /`;.`/ - ` : | |       #
 * #         \  \ `_.   \_ __\ /__ _/   .-` /  /       #
 * #     =====`-.____`.___ \_____/___.-`___.-'=====    #
 * #                       `=---='                     #
 * #     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   #
 * #                                                   #
 * #               佛祖保佑         永无BUG              #
 * #                                                   #
 */

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;

import androidx.core.view.ViewCompat;

import com.sun.lib.shadow.ShadowDrawable;

/**
 * Created by ESSC07 on 2021/10/12.
 */
public class ClipHelper {
    private final Paint clipPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    protected PorterDuffXfermode DST_OUT_MODE = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);
    protected PorterDuffXfermode DST_IN_MODE = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);

    private final Path clipPath = new Path();
    private final Path rectView = new Path();

    private ClipPathManager clipPathManager = new ClipPathManager();

    private boolean requestShapeUpdate = true;
    private View mView;
    private boolean mClipLayout = true;

    private ShadowDrawable shadowDrawable;
    private float[] borderRadii;

    public ClipHelper() {
        clipPaint.setAntiAlias(true);
        clipPaint.setColor(Color.BLUE);
        clipPaint.setStyle(Paint.Style.FILL);
        clipPaint.setStrokeWidth(1);
    }

    public void initClip(View view, boolean clipLayout, ShadowDrawable shadowDrawable, float[] borderRadii, ClipPathManager.ClipPathCreator clipPathCreator) {
        this.mView = view;
        this.shadowDrawable = shadowDrawable;
        this.borderRadii = borderRadii;
        this.mClipLayout = clipLayout;
        if (!canClip()) return;
        getView().setDrawingCacheEnabled(true);
        getView().setWillNotDraw(false);

        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
            clipPaint.setXfermode(DST_IN_MODE);
            getView().setLayerType(View.LAYER_TYPE_SOFTWARE, clipPaint);
        } else {
            clipPaint.setXfermode(DST_OUT_MODE);
            getView().setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        clipPathManager.setClipPathCreator(clipPathCreator);
        requestShapeUpdate();
    }

    private void requestShapeUpdate() {
        this.requestShapeUpdate = true;
        getView().postInvalidate();
    }

    public View getView() {
        return mView;
    }

    private boolean canClip() {
        return getView() != null && getView() instanceof ViewGroup && mClipLayout;
    }


    public void dispatchDraw(Canvas canvas) {
        if (!canClip()) return;
        if (requestShapeUpdate) {
            calculateLayout(canvas.getWidth(), canvas.getHeight());
            requestShapeUpdate = false;
        }

        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
            canvas.drawPath(clipPath, clipPaint);
        } else {
            canvas.drawPath(rectView, clipPaint);
        }

        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {
            getView().setLayerType(View.LAYER_TYPE_HARDWARE, null);
        }
    }

    private void calculateLayout(int width, int height) {
        rectView.reset();
        float left = 0f, top = 0f, right = getView().getWidth() * 1f, bottom = getView().getHeight() * 1f;
        if (shadowDrawable != null) {
            RectF rectF = shadowDrawable.getRectF();
            left = rectF.left;
            right = rectF.right;
            top = rectF.top;
            bottom = rectF.bottom;
            rectView.addRect(left, top, right, bottom, Path.Direction.CW);
            //   rectView.addRoundRect(new RectF(left,top,right,bottom),borderRadii,Path.Direction.CCW);
        } else {
            rectView.addRect(left, top, right, bottom, Path.Direction.CW);
        }

        if ((width > 0 && height > 0)) {
            clipPathManager.setupClipLayout(width, height);
            clipPath.reset();
            clipPath.set(clipPathManager.getClipPath());

            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1) {
                final boolean success = rectView.op(clipPath, Path.Op.DIFFERENCE);
            }
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && ViewCompat.getElevation(getView()) > 0f) {
                try {
                    getView().setOutlineProvider(getView().getOutlineProvider());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        getView().postInvalidate();
    }

    public void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (!canClip()) return;
        if (changed) requestShapeUpdate();
    }
}
